啥是 Java 的反射机制(reflection)? Java 反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取信息和动态调用对象方法的功能称为 Java 的反射机制。 
那为啥要整个 Java 的反射机制呢? 因为在第三方应用的开发过程中,经常会遇到某个类的方法或者属性是私有的或者只对系统开放,这时候无法直接调用,就可通过 Java 的反射机制来获取这些方法或者变量。
反射看起来破坏了封装性,可以让私有变量被外部访问到,类就不那么安全了。 Oracle 的官方文档中将发射的主要作用如下:
反射让开发人员可以通过外部类的全路径名创建对象,并使用这些类,以实现一些扩展功能。 
反射让开发人员可以枚举类的全部成员,包括构造函数、属性和方法等,以帮助开发人员写出正确的代码。 
测试时可以利用反射 API 访问类的私有变量,以保证测试代码的覆盖率。 
 
简言之,反射设计的初衷是作为开发者的一个工具,是用来帮助程序员实现一些本来不可能实现的功能的。如果没有反射,对于外部类的私有成员,我们将一筹莫展,所以我们有了反射这一后门,为程序设计提供了更大的灵活性。工具本身并没有错,关键在于如何正确地使用。
反射 API 反射 API 种类与功能 Java 类的成员包括三类:属性字段、构造函数和方法。而反射的 API 也与这些相关。如下所示
创建 demo 新建一个包,创建一个类。其中包含了需要测试的所有情况,私有属性、公有属性、公有构造方法、私有构造方法、公有方法和私有方法。
Student.java 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package  com.example.reflection;public  class  Student  {    private  String studentName;        public  int  studentAge;       public  Student ()  {       }     private  Student (String studentName)  {           this .studentName = studentName;     }     public  void  setStudentAge (int  studentAge)  {           this .studentAge = studentAge;     }     private  String show (String message)  {           System.out.println("show: "  + studentName + ","  + studentAge + ","  + message);         return  "testReturnValue" ;     } } 
API 使用对象 以下都以 com.example.reflection.Student 作为蓝本对象。
获取 class 对象 获取 class 有以下三种方式。
1 2 3 4 5 6 7 8 9 Class  studentClass  =  Class.forName("com.example.reflection.Student" );Class  studentClass2  =  Student.class;Student  studentObject  =  new  Student ();Class  studentClass3  =  studentObject.getClass();
第一种方法是通过类的全路径完整包名去获取 class 对象。这也是平时最常用的反射获取 class 对象的方法。
第二种方法有限制,需要能带入类的包。
第三种方法已经有了现成的 class 的对象了,不再需要反射来获取了。
进一步观察,我们可以将上述三种方法的结果进行打印测试一下他们是否是同一个对象。
Main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import  com.example.reflection.Student;public  class  Main  {    public  static  void  main (String[] args)  throws  Exception{                  Class  studentClass  =  Class.forName("com.example.reflection.Student" );                  Class  studentClass2  =  Student.class;                  Student  studentObject  =  new  Student ();         Class  studentClass3  =  studentObject.getClass();         System.out.println("class1 = "  + studentClass + "\n"  +             "class2 = "  + studentClass2 + "\n"  +             "class3 = "  + studentClass3 + "\n"  +             "class1 == class2 ? "  + (studentClass == studentClass2) + "\n"  +             "class2 == class3 ? "  + (studentClass2 == studentClass3));     }     } 
运行结果如下:
1 2 3 4 5 6 PS D:\Users\Desktop\work> java Main class1 = class com.example.reflection.Student class2 = class com.example.reflection.Student class3 = class com.example.reflection.Student class1 == class2 ? true class2 == class3 ? true 
通过上述三种方法获取到的对象是同一个,也就是说 Java 在运行时,每个类指挥生成一个 class 对象。 
获取到 class 对象之后就可以该怎么操作就怎么操作了。
获取成员变量 获取字段有两个 API : getDeclaredFields和 getFields 。前者用于获取所有声明的字段,包括公有的字段和私有的字段;后者仅仅用了获取公有字段。
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import  java.lang.reflect.Field;System.out.println("\nall Fields declared:" ); Field[] declaredFieldList = studentClass.getDeclaredFields(); for  (Field declaredField : declaredFieldList) {    System.out.println("declared Field: "  + declaredField); } System.out.println("\nall public Fields declared:" ); Field[] fieldList = studentClass.getFields(); for  (Field field : fieldList) {    System.out.println("field: "  + field); } 
运行结果如下所示:
1 2 3 4 5 6 7 8 PS D:\Users\Desktop\work> java Main all Fields declared: declared Field: private java.lang.String com.example.reflection.Student.studentName declared Field: public int com.example.reflection.Student.studentAge all public Fields declared: field: public int com.example.reflection.Student.studentAge 
获取构造方法 获取构造方法同样包含两个 API :用于获取所有构造方法的 getDeclaredConstructors 和用于获取公有构造方法的 getConstructors 。
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import  java.lang.reflect.Constructor;System.out.println("\nall Constructors declared:" ); Constructor[] declaredConstructorList = studentClass.getDeclaredConstructors(); for  (Constructor declaredConstructor : declaredConstructorList) {    System.out.println("declared Constructor: "  + declaredConstructor); } System.out.println("\nall public Constructors declared:" ); Constructor[] constructorList = studentClass.getConstructors(); for  (Constructor constructor : constructorList) {    System.out.println("constructor: "  + constructor); } 
运行结果如下所示:
1 2 3 4 5 6 7 8 PS D:\Users\Desktop\work> java Main all Constructors declared: declared Constructor: public com.example.reflection.Student() declared Constructor: private com.example.reflection.Student(java.lang.String) all public Constructors declared: constructor: public com.example.reflection.Student() 
获取非构造方法 获取非构造方法的两个 API 是:获取所有声明的非构造函数的 getDeclaredMethods 和仅获取公有非构造函数的 getMethods 。
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import  java.lang.reflect.Method;System.out.println("\nall Methods declared:" ); Method[] declaredMethodList = studentClass.getDeclaredMethods(); for  (Method declaredMethod : declaredMethodList) {    System.out.println("declared Method: "  + declaredMethod); } System.out.println("\nall public Methods declared:" ); Method[] methodList = studentClass.getMethods(); for  (Method method : methodList) {    System.out.println("method: "  + method); } 
输出结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 PS D:\Users\Desktop\work> java Main all Methods declared: declared Method: private java.lang.String com.example.reflection.Student.show(java.lang.String) declared Method: public void com.example.reflection.Student.setStudentAge(int) all public Methods declared: method: public void com.example.reflection.Student.setStudentAge(int) method: public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException method: public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException method: public final void java.lang.Object.wait() throws java.lang.InterruptedException method: public boolean java.lang.Object.equals(java.lang.Object) method: public java.lang.String java.lang.Object.toString() method: public native int java.lang.Object.hashCode() method: public final native java.lang.Class java.lang.Object.getClass() method: public final native void java.lang.Object.notify() method: public final native void java.lang.Object.notifyAll() 
这里可以看到 getMethods 不仅获取到了自定义的公有方法,还可以获取到父类( Object )的公有方法。但是 getDeclaredMethods 无法获取到父类中的方法。 
上述四种获取方法完整程序:
Main.java 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 import  com.example.reflection.Student;import  java.lang.reflect.Field;import  java.lang.reflect.Constructor;import  java.lang.reflect.Method;public  class  Main  {    public  static  void  main (String[] args)  throws  Exception{                  Class  studentClass  =  Class.forName("com.example.reflection.Student" );                  Class  studentClass2  =  Student.class;                  Student  studentObject  =  new  Student ();         Class  studentClass3  =  studentObject.getClass();         System.out.println("class1 = "  + studentClass + "\n"  +             "class2 = "  + studentClass2 + "\n"  +             "class3 = "  + studentClass3 + "\n"  +             "class1 == class2 ? "  + (studentClass == studentClass2) + "\n"  +             "class2 == class3 ? "  + (studentClass2 == studentClass3));         System.out.println("\nall Fields declared:" );                  Field[] declaredFieldList = studentClass.getDeclaredFields();         for  (Field declaredField : declaredFieldList) {             System.out.println("declared Field: "  + declaredField);         }         System.out.println("\nall public Fields declared:" );                  Field[] fieldList = studentClass.getFields();         for  (Field field : fieldList) {             System.out.println("field: "  + field);         }         System.out.println("\nall Constructors declared:" );                  Constructor[] declaredConstructorList = studentClass.getDeclaredConstructors();         for  (Constructor declaredConstructor : declaredConstructorList) {             System.out.println("declared Constructor: "  + declaredConstructor);         }         System.out.println("\nall public Constructors declared:" );                  Constructor[] constructorList = studentClass.getConstructors();         for  (Constructor constructor : constructorList) {             System.out.println("constructor: "  + constructor);         }         System.out.println("\nall Methods declared:" );                  Method[] declaredMethodList = studentClass.getDeclaredMethods();         for  (Method declaredMethod : declaredMethodList) {             System.out.println("declared Method: "  + declaredMethod);         }         System.out.println("\nall public Methods declared:" );                  Method[] methodList = studentClass.getMethods();         for  (Method method : methodList) {             System.out.println("method: "  + method);         }     }     } 
完整实现反射调用 直接贴代码如下,建议先自己手打再对比。
Main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import  java.lang.reflect.Field;import  java.lang.reflect.Constructor;import  java.lang.reflect.Method;public  class  Main  {    public  static  void  main (String[] args)  throws  Exception {                  Class  studentClass  =  Class.forName("com.example.reflection.Student" );                  Constructor  studentConstructor  =  studentClass.getDeclaredConstructor(String.class);                           studentConstructor.setAccessible(true );                  Object  student  =  studentConstructor.newInstance("studentNameA" );                  Field  studentAgeField  =  studentClass.getDeclaredField("studentAge" );                           studentAgeField.set(student, 100 );                  Method  studentShowMethod  =  studentClass.getDeclaredMethod("show" , String.class);                  studentShowMethod.setAccessible(true );                  Object  result  =  studentShowMethod.invoke(student, "message" );         System.out.println("result: "  + result);     } } 
运行程序的输出结果如下所示,第二行输出是 Student.show() 的调用产生的。第三行则是 Main.java 打印的调用的返回结果。
1 2 3 PS D:\Users\Desktop\work> java Main show: studentNameA,100,message result: testReturnValue 
若要查询更多方法或者 API 则可以查看参考链接一或者官方文档。 
参考链接 参考链接一:(主要写了各种接口方法等) https://www.jianshu.com/p/9be58ee20dee 
参考链接二: https://zhuanlan.zhihu.com/p/86293659